#include <iostream>
#include <future>
#include <thread>
#include <memory>
#include <vector>
#include <functional>

// 成员:互斥锁，同步，线程池，任务池，isrunning
// 操作:push放任务，stop线程池停止
static const int gdefaultthreads = 4;
class ThreadPool
{
    using task_t = std::function<void()>;

public:
    ThreadPool()
        : _isrunning(true){
        for (int i = 0; i < gdefaultthreads; i++)
        {
            _threads.emplace_back(&ThreadPool::entry, this);
        }
    }

    template <class F, class... Args>
    auto push(F &&func, Args &&...args) -> std::future<decltype(func(args...))>
    {
        // 1.获取返回类型
        using return_type = decltype(func(args...));
        // 2.将对象绑定成无参的可调用对象
        auto fun = std::bind(std::forward<F>(func), std::forward<Args>(args)...);
        // 3.packaged打包
        auto task_ptr = std::make_shared<std::packaged_task<return_type()>>(fun);

        // 4.利用lambda将任务放到任务池
        // 建立关联
        std::future<return_type> fu = task_ptr->get_future();
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 放数据,唤醒线程池
            _tasks.push_back([task_ptr]()
                             { (*task_ptr)(); });
            _cond.notify_one();
        }
        return fu;
    }
    void stop()
    {
        if (!_isrunning)
            return;
        _isrunning = false;
        _cond.notify_all();
        for (auto &thread : _threads)
            thread.join();
    }

    ~ThreadPool(){stop();}

private:
    void entry() // 线程的入口
    {
        while (_isrunning)
        {
            std::vector<task_t> temp_tasks;
            {
                std::unique_lock<std::mutex> lock(_mutex);
                //等待任务不为空或者线程池停止
                _cond.wait(lock,[this](){
                    return !_tasks.empty()||!_isrunning;
                });
                temp_tasks.swap(_tasks);
            }
            //线程独立的task_pool，不会互相影响
            for(auto & task:temp_tasks)
                task();
        }
    }

private:
    std::mutex _mutex;             // 维护取、放数据
    std::condition_variable _cond; // 条件变量
    std::vector<task_t> _tasks;    // 任务池
    std::vector<std::thread> _threads;
    bool _isrunning;
};

int add (int x ,int y)
{
    return x+y;
}

int main()
{
    ThreadPool threadpool;
    
    for(int i=0;i<10;i++)
    {
        std::future<int> fu=threadpool.push(add,i,0);
        std::cout<<fu.get()<<" ";
    }
    std::cout<<std::endl;
    threadpool.stop();
    return 0;
}